//! sie寄存器0x104， S模式下的中断使能寄存器
//!

use crate::bits;
use core::arch::asm;

#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Sie {
    bits: usize,
}
impl Sie {
    pub const BITMASK: usize = 0x222;

    pub const fn from_bits(bits: usize) -> Self {
        Self { bits: bits & 0x222 }
    }

    pub const fn bits(&self) -> usize {
        self.bits & 0x222
    }

    pub const fn bitmask(&self) -> usize {
        Self::BITMASK
    }
}

#[inline(always)]
unsafe fn _read() -> usize {
    unsafe {
        let r: usize;
        asm!(
            "csrrs {0}, 0x104, zero",
            out(reg) r
        );
        r
    }
}

#[inline]
pub fn read() -> Sie {
    Sie {
        bits: unsafe { _read() },
    }
}

#[inline(always)]
unsafe fn _write(bits: usize) {
    unsafe {
        asm!(
            "csrrw zero, 0x104, {0}",
            in(reg) bits,
        );
    }
}

#[inline]
pub fn write(value: Sie) {
    unsafe {
        _write(value.bits);
    }
}

impl Sie {
    /// read Supervisor Software Interrupt Enable
    #[inline]
    pub fn ssoft(&self) -> bool {
        bits::bf_extract(self.bits, 1, 1) != 0
    }

    /// Supervisor Software Interrupt Enable
    #[inline]
    pub fn set_ssoft(&mut self, set_ssoft: bool) {
        self.bits = bits::bf_insert(self.bits, 1, 1, set_ssoft as usize);
    }

    /// Supervisor Timer Interrupt Enable
    #[inline]
    pub fn stimer(&self) -> bool {
        bits::bf_extract(self.bits, 5, 1) != 0
    }

    /// Supervisor Timer Interrupt Enable
    #[inline]
    pub fn set_stimer(&mut self, set_stimer: bool) {
        self.bits = bits::bf_insert(self.bits, 5, 1, set_stimer as usize);
    }

    ///  Supervisor External Interrupt Enable
    #[inline]
    pub fn sext(&self) -> bool {
        bits::bf_extract(self.bits, 9, 1) != 0
    }

    ///  Supervisor External Interrupt Enable
    #[inline]
    pub fn set_sext(&mut self, set_sext: bool) {
        self.bits = bits::bf_insert(self.bits, 9, 1, set_sext as usize);
    }
}

#[inline(always)]
unsafe fn _set(bits: usize) {
    unsafe {
        asm!(
          "csrrs zero, 0x104, {0}",
            in(reg) bits,
        );
    }
}

#[inline(always)]
unsafe fn _clear(bits: usize) {
    unsafe {
        asm!(
            "csrrc zero, 0x104, {0}",
            in(reg) bits,
        );
    }
}

/// Supervisor Software Interrupt Enable
#[inline]
pub fn set_ssoft() {
    unsafe {
        _set(1 << 1);
    }
}

/// Supervisor Software Interrupt Enable
#[inline]
pub fn clear_ssoft() {
    unsafe {
        _clear(1 << 1);
    }
}

/// Supervisor Timer Interrupt Enable
#[inline]
pub fn set_stimer() {
    unsafe {
        _set(1 << 5);
    }
}
/// Supervisor Timer Interrupt Enable
#[inline]
pub fn clear_stimer() {
    unsafe {
        _clear(1 << 5);
    }
}

/// Supervisor External Interrupt Enable
#[inline]
pub fn set_sext() {
    unsafe {
        _set(1 << 9);
    }
}

/// Supervisor External Interrupt Enable
#[inline]
pub fn clear_sext() {
    unsafe {
        _clear(1 << 9);
    }
}
